package ${rootPackage}.actions;

import java.util.List;

import ${rootPackage}.models.${modelClassName};
import ${rootPackage}.services.${modelClassName}Service;

import org.apache.struts2.convention.annotation.Result;
import org.apache.struts2.convention.annotation.Action;
import org.apache.struts2.convention.annotation.Actions;
import org.apache.struts2.convention.annotation.Results;
import org.apache.struts2.convention.annotation.Namespace;
import org.apache.struts2.convention.annotation.InterceptorRef;

import com.opensymphony.xwork2.validator.annotations.Validations;
import com.opensymphony.xwork2.validator.annotations.ValidatorType;
import com.opensymphony.xwork2.Preparable;
import com.opensymphony.xwork2.ActionSupport;

import com.opensymphony.xwork2.validator.annotations.RequiredFieldValidator;
import com.opensymphony.xwork2.validator.annotations.RequiredStringValidator;
import com.opensymphony.xwork2.validator.annotations.StringLengthFieldValidator;

import org.springframework.stereotype.Component;
import org.springframework.context.annotation.Scope;

@Component
@Scope("prototype")
@Namespace("/${actionName}")
public class ${actionClassName} extends ActionSupport implements Preparable {
    private ${modelClassName} model;
    private Long id;
    private List<${modelClassName}> list;
    private ${modelClassName}Service service;

    @Action("list")
    public String list() {
        list = service.getAll();
        return SUCCESS;
    }

    @Actions({
        @Action(value = "edit", interceptorRefs = {@InterceptorRef("paramsPrepareParamsStack")}),
        @Action(value = "new")
    })
    public String input() {
        return INPUT;
    }

    @Action(value = "delete", results = {@Result(name = "success", type = "redirect", location = "list")})
    public String delete() {
        service.remove(id);
        return SUCCESS;
    }

    @Action(
        value = "createOrUpdate",
        results = {
            @Result(name = "success", type = "redirect", location = "list.action"),
            @Result(name = "input", location = "/WEB-INF/content/${actionName}/new-input.jsp")
        },
        interceptorRefs = {@InterceptorRef("paramsPrepareParamsStack")}
    )
    <%
        //TODO: replace this with a builder
        import static org.apache.commons.lang.StringUtils.capitalize as capitalize
        //constraints is a map of [fieldName : FieldConstraint{constaints: [constraintName: value]}]
        if (constraints) {
            println '@Validations('
            StringBuilder fields = new StringBuilder()
            StringBuilder strings = new StringBuilder()
            StringBuilder stringLengthFields = new StringBuilder()
            constraints.each {key, value->
                Map fieldConstraints = value.constraints
                // fieldConstraints.get('nullable') could be null
                if (false == fieldConstraints.get('nullable')) {
                    switch(value.type) {
                        case 'primitive':
                            fields.append("@RequiredFieldValidator(type = ValidatorType.SIMPLE, fieldName = \"model.${key}\", message = \"You must enter a value for ${capitalize(key)}.\"),")
                        break                            
                        case 'string':
                            strings.append("@RequiredStringValidator(type = ValidatorType.SIMPLE, fieldName = \"model.${key}\", message = \"You must enter a value for ${capitalize(key)}.\"),")
                        break
                    }
                }
                if (fieldConstraints.containsKey('length')) {
                    //it has to be an string right?
                    def maxLength = fieldConstraints.get('length')
                    switch(value.type) {
                       case 'string':
                            stringLengthFields.append("@StringLengthFieldValidator(type = ValidatorType.SIMPLE, maxLength=\"${maxLength}\", fieldName = \"model.${key}\", message = \"${capitalize(key)} must not exceed ${maxLength} characters.\"),")
                       break
                    }
                }
            }
            if (strings) {
                //remove trailing comma
                def padding = '\t' * 2;
                print "${padding}requiredStrings = {${strings.substring(0, strings.size() - 1)}}"
            }
            if (stringLengthFields) {
                //remove trailing comma
                def padding = '\t' * 2;
                if (strings)
                    println ','
                print "${padding}stringLengthFields = {${stringLengthFields.substring(0, stringLengthFields.size() - 1)}}"
            }
            if (fields) {
                //remove trailing comma
                def padding = '\t' * 2;
                if (stringLengthFields)
                    println ','
                print "${padding}requiredFields = {${fields.substring(0, fields.size() - 1)}}"
            }

            println ''
            print '\t)'
       }
    %>
    public String createOrUpdate() {
        service.save(model);
        return SUCCESS;
    }

    public void prepare() throws Exception {
        if (id != null)
            model = service.get(id);
    }

    public void setId(Long id) {
        this.id = id;
    }
    
    public Long getId() {
        return id;
    }

    public ${modelClassName} getModel() {
        return model;
    }

    public void setModel(${modelClassName} model)  {
        this.model = model;
    }

    public List<${modelClassName}> getModelList() {
        return list;
    }

    //inject service
    public void set${modelClassName}Service(${modelClassName}Service service) {
        this.service = service;
    }
}
